package xxl.robotlegs.extensions.matching.impl 
{
	import xxl.robotlegs.extensions.matching.api.ITypeFilter;
	import xxl.robotlegs.extensions.matching.api.ITypeMatcher;
	import xxl.robotlegs.extensions.matching.api.ITypeMatcherFactory;
	/**
	 * ...
	 * @author XXL
	 */
	public class TypeMatcher implements ITypeMatcher, ITypeMatcherFactory
	{
		protected const _allOfTypes:Vector.<Class> = new Vector.<Class>;
		protected const _anyOfTypes:Vector.<Class> = new Vector.<Class>;
		protected const _noneOfTypes:Vector.<Class> = new Vector.<Class>;
		protected var _typeFilter:ITypeFilter;
		
		public function TypeMatcher() 
		{
			
		}
		
		public function allOf(...types):TypeMatcher
		{
			pushAddedTypesTo(types, _allOfTypes);
			return this;
		}
		
		public function anyOf(...types):TypeMatcher
		{
			pushAddedTypesTo(types, _anyOfTypes);
			return this;
		}
		
		public function noneOf(...types):TypeMatcher
		{
			pushAddedTypesTo(types, _noneOfTypes);
			return this;
		}
		
		public function lock():ITypeMatcherFactory
		{
			createTypeFilter();
			return this;
		}
		
		//----------private/protected
		
		protected function pushAddedTypesTo(types:Array, targetSet:Vector.<Class>):void
		{
			_typeFilter && throwSealedMatcherError();
			
			pushValuesToClassVector(types, targetSet);
		}
		
		protected function throwSealedMatcherError():void
		{
			throw new TypeMatcherError(TypeMatcherError.SEALED_MATCHER);
		}
		
		protected function pushValuesToClassVector(values:Array, vector:Vector.<Class>):void
		{
			var type:Class;
			if (values.length == 1 && (values[0] is Array || values[0] is Vector.<Class>))
			{
				for each(type in values[0])
				{
					vector.push(type);
				}
			}
			else
			{
				for each(type in values)
				{
					vector.push(type);
				}
			}
		}
		
		protected function buildTypeFilter():ITypeFilter
		{
			if ((_allOfTypes.length == 0)
				&& (_anyOfTypes.length == 0)
				&& (_noneOfTypes.length == 0))
			{
				throw new TypeMatcherError(TypeMatcherError.EMPTY_MATCHER);
			}
			return new TypeFilter(_allOfTypes, _anyOfTypes, _noneOfTypes);
		}
		
		/* INTERFACE xxl.robotlegs.extensions.matching.api.ITypeMatcher */
		
		public function createTypeFilter():ITypeFilter 
		{
			return _typeFilter ||= buildTypeFilter();
		}
		
		/* INTERFACE xxl.robotlegs.extensions.matching.api.ITypeMatcherFactory */
		
		public function clone():ITypeMatcher 
		{
			return new TypeMatcher().allOf(_allOfTypes).anyOf(_anyOfTypes).noneOf(_noneOfTypes);
		}
		
	}

}